from datetime import datetime
import json

import requests
from django.contrib.auth import get_user_model, hashers
from django.db import transaction
from django.db.models import Prefetch
from django.conf import settings
from rest_framework.filters import OrderingFilter
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView, Response, status
from rest_framework import viewsets, mixins
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework_simplejwt.views import TokenViewBase
from rest_framework.decorators import action
from rest_framework import filters
from django_filters.rest_framework import DjangoFilterBackend

from .models import Role, Permission, AccountRoles, RolePermissions, Account
from .filters import AccountFilter, RoleFilter, TeacherFilter
from .serializers import RoleListSerializer, PermsListSerializer, AccountSerializer, RoleCreateSerializer, \
    AccountUpdateSerializer, CustomTokenRefreshSerializer, TeacherSerializer
from utils.common import Pagination
from ..school.models import Faculty
from ..school.utils import get_second_faculty_by_perms

User = get_user_model()


def get_tokens_for_user(user):
    refresh = RefreshToken.for_user(user)

    return {
        'refresh_token': str(refresh),
        'token': str(refresh.access_token),
    }


class LoginView(APIView):

    def post(self, request):
        username = request.data.get('username', '')
        password = request.data.get('password', '')
        try:
            user = Account.objects.get(username=username)

            if not hashers.check_password(password, user.password):
                return Response({'message': '密码错误'}, status=status.HTTP_400_BAD_REQUEST)
            if not user.is_active:
                return Response({'message': '账号已被冻结'}, status=status.HTTP_400_BAD_REQUEST)
            if not user.can_login_system:
                return Response({'message': '该账号无法登陆到系统'}, status=status.HTTP_400_BAD_REQUEST)

            response_data = get_tokens_for_user(user)
            user.last_login = datetime.now()
            user.save()

        except Account.DoesNotExist:
            return Response({'message': '账号错误'}, status=status.HTTP_400_BAD_REQUEST)

        return Response({'data': response_data}, status=status.HTTP_200_OK)


class UserInfoView(APIView):
    """
    get:
        获取用户信息
    """
    permission_classes = [IsAuthenticated, ]

    def get(self, request):
        """
        返回用户的信息
        权限列表，roles: ['perm1','perm2',...]
        """
        user = request.user
        perms_set = user.get_all_perms()
        perms = list(perms_set) if perms_set else ['nothing']
        res_data = {'name': user.realname, 'roles': perms}
        return Response({'data': res_data}, status=status.HTTP_200_OK)


class AccountViewSet(mixins.ListModelMixin,
                     mixins.UpdateModelMixin,
                     viewsets.GenericViewSet):
    queryset = User.objects.all()
    pagination_class = Pagination
    serializer_class = AccountSerializer
    permission_classes = [IsAuthenticated]
    filter_backends = (DjangoFilterBackend, filters.OrderingFilter)
    filter_class = AccountFilter
    ordering_fields = ('id',)

    def get_queryset(self):
        if self.action == 'list':
            return User.objects.prefetch_related(
                Prefetch('roles', queryset=Role.objects.only('id', 'name', 'display'))
            )
        return self.queryset

    def list(self, request, *args, **kwargs):
        # 需要有学院的code才能获取数据, 因为是get方法，所以不用管某些人越权获取到没权限查看的学院的用户
        faculty_code = request.query_params.get('faculty_code', None)
        if faculty_code is None:
            queryset = Account.objects.none()
        else:
            queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        else:
            data = queryset.values('id', 'username', 'realname')
            return Response(data)


    def update(self, request, *args, **kwargs):
        roles = request.data.get('roles', None)
        instance = self.get_object()

        try:
            roles_set = set(roles)
        except TypeError:
            return Response({'message': '需要正确的角色参数'}, status=status.HTTP_400_BAD_REQUEST)

        user_role_qs = AccountRoles.objects.filter(account_id=instance.id).values_list('role_id', flat=True)
        user_role_ids_set = set([role_id for role_id in user_role_qs])
        will_add = roles_set - user_role_ids_set  # 新增的角色
        will_delete = user_role_ids_set - roles_set  # 要删除的角色
        will_create_objs = [AccountRoles(account_id=instance.id, role_id=role_id) for role_id in will_add]
        will_delete_objs = AccountRoles.objects.filter(account_id=instance.id, role_id__in=will_delete)
        try:
            with transaction.atomic():
                serializer = AccountUpdateSerializer(instance, data=request.data, partial=True,
                                                     context={'request_user_is_superuser': request.user.is_superuser})
                serializer.is_valid(raise_exception=True)
                serializer.save()
                will_delete_objs.delete()
                AccountRoles.objects.bulk_create(will_create_objs)
        except Exception as e:
            return Response({'message': f'更新失败, 原因: {e.args}'}, status=status.HTTP_400_BAD_REQUEST)

        res_data = serializer.data
        return Response(res_data)

    @action(methods=['get'], detail=False, url_path='search_user')
    def search_user(self, request, pk=None):
        """ 查询用户 """
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)


class RoleViewSet(mixins.ListModelMixin,
                  mixins.UpdateModelMixin,
                  viewsets.GenericViewSet):
    serializer_class = RoleListSerializer
    permission_classes = [IsAuthenticated]
    queryset = Role.objects.prefetch_related('permissions').all()
    filter_backends = (DjangoFilterBackend,)
    filter_class = RoleFilter

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        # 根据请求者能看的学院，返回属于这些学院的角色
        if not request.user.is_superuser:
            can_view_faculty = get_second_faculty_by_perms(request.user, add_both=True)
            can_view_faculty_code = [i['faculty_code'] for i in can_view_faculty]
            if 'view_all_second_faculty' not in can_view_faculty_code:
                queryset = queryset.filter(codename__in=can_view_faculty_code)

        faculty_qs = Faculty.objects.all().values('faculty_code', 'faculty_title')
        faculty_dict = {i['faculty_code']: i['faculty_title'] for i in faculty_qs}

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            for i in serializer.data:
                i['faculty_title'] = faculty_dict.get(i['codename'], '')
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        for i in serializer.data:
            i['faculty_title'] = faculty_dict.get(i['codename'], '')
        return Response(serializer.data)

    def update(self, request, *args, **kwargs):
        role = self.get_object()
        perms = request.data.get('permissions', [])
        serializer = RoleCreateSerializer(role, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        role_id = role.id
        perms_set = set(perms)
        role_perms = role.permissions.all()
        role_perms_set = set([perm.id for perm in role_perms])
        will_add = perms_set - role_perms_set
        will_delete = role_perms_set - perms_set

        objs = [RolePermissions(role_id=role_id, permission_id=perm_id) for perm_id in will_add]

        with transaction.atomic():
            save_id = transaction.savepoint()
            try:
                serializer.save()
                RolePermissions.objects.filter(role_id=role_id, permission_id__in=will_delete).delete()
                RolePermissions.objects.bulk_create(objs)
            except Exception as e:
                print(e)
                transaction.savepoint_rollback(save_id)
                return Response({'message': '更新角色失败'}, status=status.HTTP_400_BAD_REQUEST)
            transaction.savepoint_commit(save_id)

        res_data = serializer.data
        res_data['permissions'] = perms
        return Response(res_data)

    @action(methods=['post'], detail=True, url_path='set_role_person')
    def set_role_person(self, request, pk=None):
        """ 批量设置某个角色的成员 """
        if not request.user.is_superuser:
            all_perms = request.user.get_all_perms()  # 获取全部权限
            if 'prize_set_people' not in all_perms:
                return Response({'message': '您没有权限设置该角色的成员。'}, status=status.HTTP_403_FORBIDDEN)

        person_lst = request.data.get('person', [])
        person_set = set(person_lst)
        instance = Role.objects.filter(id=pk).values('name').first()
        if not instance:
            return Response({'message': '错误的id'}, status=status.HTTP_400_BAD_REQUEST)

        # 找出该角色全部成员id
        role_person_ids = AccountRoles.objects.filter(role_id=pk).values_list('account_id', flat=True)
        role_person_ids_set = set([i for i in role_person_ids])
        will_add = person_set - role_person_ids_set  # 新增的用户
        will_delete = role_person_ids_set - person_set  # 要删除的用户
        will_create_objs = [AccountRoles(account_id=account_id, role_id=pk) for account_id in will_add]
        will_delete_objs = AccountRoles.objects.filter(account_id__in=will_delete, role_id=pk)
        try:
            with transaction.atomic():
                will_delete_objs.delete()
                AccountRoles.objects.bulk_create(will_create_objs)
        except Exception as e:
            return Response({'message': f'设置成员失败, 原因: {e.args}'}, status=status.HTTP_400_BAD_REQUEST)

        return Response({'message': 'ok'})


class PermissionViewSet(mixins.ListModelMixin,
                        viewsets.GenericViewSet):
    """
    list:
        以树结构显示所有权限
    """
    queryset = Permission.objects.all()
    permission_classes = [IsAuthenticated]
    serializer_class = PermsListSerializer

    def list(self, request, *args, **kwargs):
        """ 重写list方法, 以树结构返回所有权限 """
        queryset = Permission.objects.all().order_by('sort_num')
        system_name = request.query_params.get('system_name', None)
        if system_name:
            queryset = queryset.filter(system_name=system_name)
        serializer = self.get_serializer(queryset, many=True)
        perms_list = serializer.data

        # 利用list的可变对象属性，实现树形结构

        perms_dict = {}
        for perm in perms_list:
            perms_dict[perm['id']] = perm
            perms_dict[perm['id']]['child'] = []

        response_data = []
        for perm in perms_list:
            parent = perm['parent']
            if parent:
                perms_dict[parent]['child'].append(perm)
            else:
                response_data.append(perm)  # 只返回一级目录的数据

        return Response(response_data)


class MyTokenRefreshView(TokenViewBase):
    """
    自定义刷新token refresh: 刷新token的元素
    """
    serializer_class = CustomTokenRefreshSerializer


